﻿// =====================================================================
// <copyright file="ConfigManager.PMethods.cs" author="David R. Guindo">
// 	Copyright (C) 2013. All rights reserved.
// </copyright>
// =====================================================================

namespace AppBlock.Config
{
    using System;
    using System.Collections.Generic;
    using System.Configuration;
    using System.IO;
    using System.Linq;
    using System.Reflection;

    public static partial class ConfigManager
    {
        private static void ProcessConfigFiles(Dictionary<string, string> values, string path, bool hasPreference = true)
        {
            foreach (string file in Directory.GetFiles(path, Configfilename))
                SetConfigurationFile(file, values, hasPreference);
        }

        private static void SetConfigurationFile(string file, Dictionary<string, string> values,
            bool hasPreference = true)
        {
            var configMap = new ExeConfigurationFileMap { ExeConfigFilename = file };

            try
            {
                var config = ConfigurationManager.OpenMappedExeConfiguration(configMap, ConfigurationUserLevel.None);

                if (defaultSections == null)
                {
                    var cfg = ConfigurationManager.OpenMachineConfiguration();
                    defaultSections = new List<string>();
                    foreach (string key in cfg.Sections.Keys)
                    {
                        defaultSections.Add(key);
                    }
                }

                foreach (ConfigurationSection cs in config.Sections)
                {
                    if (!CustomSections.ContainsKey(cs.SectionInformation.Name))
                    {
                        if (cs.SectionInformation.Type.Contains("System.Configuration.IgnoreSection")) continue;
                        //Remember include Section in config file for have te correct type of ConfigurationSection (warn if DefaultConfigurationSection)
                        CustomSections.Add(cs.SectionInformation.Name, cs);
                    }
                }

                foreach (KeyValueConfigurationElement setting in config.AppSettings.Settings)
                {
                    if (!ConfigurationManager.AppSettings.AllKeys.Contains(setting.Key))
                    {
                        ConfigurationManager.AppSettings.Set(setting.Key, setting.Value);
                    }
                    else
                    {
                        if (hasPreference) ConfigurationManager.AppSettings[setting.Key] = setting.Value;
                    }
                }

                foreach (ConnectionStringSettings con in config.ConnectionStrings.ConnectionStrings)
                {
                    if (ConfigurationManager.ConnectionStrings[con.Name] == null)
                    {
                        var fi = typeof(ConfigurationElementCollection).GetField("bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
                        fi.SetValue(ConfigurationManager.ConnectionStrings, false);
                        ConfigurationManager.ConnectionStrings.Add(con);
                    }
                    else
                    {
                        if (hasPreference)
                        {
                            //This block is a work around over "is read only" exception when connection string is modified
                            var constr = ConfigurationManager.ConnectionStrings[con.Name];
                            var fi = typeof(ConfigurationElement).GetField("_bReadOnly", BindingFlags.Instance | BindingFlags.NonPublic);
                            fi.SetValue(constr, false);

                            constr.ProviderName = con.ProviderName;
                            constr.ConnectionString = con.ConnectionString;
                        } 
                    }
                }
            }
            catch (Exception ex)
            {
                throw new Exception("AppBlock.Config Exception: " + ex.Message, ex);
            }
        }
    }
}